import {newArrayProto} from "./array";

export function observe(data) {
  // 对对象进行劫持
  if(typeof data !== 'object' || data === null) {
    return;
  }

  // 劫持过就不需要再被劫持
  if (data.__ob__ instanceof Observe) {
    return data.__ob__;
  }
  return new Observe(data);
}

class Observe {
  constructor(data) {
    Object.defineProperty(data, '__ob__', {
      value: this,
      enumerable: false, // 不可枚举
    })
    data.__ob__ = this;
    // Object.defineProperty 只能劫持已经存在的 $set
    if (Array.isArray(data)) {
      data.__proto__ = newArrayProto;
      this.observeArray(data);
    } else {
      this.walk(data);
    }
  }
  walk(data) {
    Object.keys(data).forEach(key =>
      defineReactive(data, key, data[key]));
  }
  observeArray(data) {
    data.forEach(item => observe(item))
  }
}

export function defineReactive(data, key, value) {
  observe(value);
  Object.defineProperty(data, key, {
    get() {
      return value;
    },
    set(newValue) {
      if (newValue !== value) {
        observe(newValue);
        value = newValue;
      }
    }
  })
}
